home *** CD-ROM | disk | FTP | other *** search
/ Experimental BBS Explossion 3 / Experimental BBS Explossion III.iso / games / nhak_src.zip / OVLMGR.ASM < prev    next >
Assembly Source File  |  1993-03-16  |  42KB  |  1,862 lines

  1. ;    SCCS Id: @(#)ovlmgr.asm         90/05/27
  2. ;  Copyright (c) 1989, 1990 Pierre Martineau and Stephen Spackman. All Rights Reserved.
  3. ;  This product may be freely redistributed.  See NetHack license for details.
  4.  
  5. VERSION     EQU    3081h
  6.  
  7.         PAGE    57,132
  8.         TITLE    'DOS Overlay Manager for MSC 5.1+'
  9.         SUBTTL    'Copyright (c) 1989, 1990 Pierre Martineau and Stephen Spackman. All Rights Reserved.'
  10.  
  11. ; acknowledgements:   - Many thanks to Norm Meluch for his invaluable help
  12. ;              - No thanks to Microsoft
  13. ;              - alltrsidsctysti!!!
  14. ;              - izchak and friends for impetus
  15. ;              - us for brilliance
  16. ;              - coffee for speed
  17. ;              - others as necessary
  18.  
  19. ; assumptions:          - all registers are preserved including flags
  20. ;              - the stack is preserved
  21. ;              - re-entrancy is not required
  22.  
  23. DOSALLOC    EQU    48h            ; memory allocation
  24. DOSFREE     EQU    49h            ; free allocated memory
  25. DOSREALLOC    EQU    4ah            ; modify memory block
  26. DOSREAD     EQU    3fh            ; read bytes from handle
  27. DOSSEEK     EQU    42h            ; logical handle seek
  28. DOSOPEN     EQU    3dh            ; open handle
  29. DOSCLOSE    EQU    3eh            ; close handle
  30. DOSEXEC     EQU    4bh            ; exec child process
  31. DOSPUTC     EQU    02h            ; print a char
  32. DOSVERSION    EQU    30h            ; get version number
  33. DOSGETVEC    EQU    35h            ; get interrupt vector
  34. DOS        EQU    21h            ; Dos interrupt #
  35. PRINT        EQU    09h            ; print string
  36. TERMINATE    EQU    4ch            ; terminate process
  37. EMM        EQU    67h            ; EMM handler int vector
  38. EMMSTATUS    EQU    40h            ; get EMM status
  39. EMMFRAME    EQU    41h            ; get EMM page frame
  40. EMMTOTALS    EQU    42h            ; get EMM pages available
  41. EMMALLOC    EQU    43h            ; allocate EMM pages
  42. EMMMAP        EQU    44h            ; map EMM pages
  43. EMMFREE     EQU    45h            ; free EMM pages
  44. CR        EQU    0dh
  45. LF        EQU    0ah
  46. ESCAPE        EQU    1bh
  47. BELL        EQU    07h
  48. PARSIZ        EQU    10h            ; this is the size of a paragraph - this better not change!
  49. FAERIE        EQU    00h            ; Used for dummy segment allocation
  50.  
  51. NOERR        EQU    0
  52. DOSERR        EQU    1
  53. FILEERR     EQU    2
  54. NOMEMERR    EQU    3
  55. FILEIOERR    EQU    4
  56. VICTIMERR    EQU    5
  57. RELERR        EQU    6
  58. EMSERR        EQU    7
  59. HDRERR        EQU    8
  60.  
  61. ; The following EXTRNs are supplied by the linker
  62.  
  63. EXTRN        $$OVLBASE:BYTE            ; segment of OVERLAY_AREA
  64. EXTRN        $$MPGSNOVL:BYTE         ; ^ to module table
  65. EXTRN        $$MPGSNBASE:WORD        ; ^ to module segment fixups
  66. EXTRN        $$INTNO:BYTE            ; interrupt number to be used
  67. EXTRN        $$COVL:WORD            ; number of physical overlays
  68. EXTRN        $$CGSN:WORD            ; number of modules
  69. EXTRN        $$MAIN:FAR            ; ^ to function main()
  70.  
  71. PUBLIC        $$OVLINIT            ; Our entry point
  72.                         ; called by the c startup code
  73. IFDEF i386
  74. OP32        MACRO                ; 32 bit operand override
  75.         DB    066h
  76.         ENDM
  77.  
  78. pusha        MACRO                ; push all registers
  79.         DB    060h
  80.         ENDM
  81.  
  82. popa        MACRO                ; pop all registers
  83.         DB    061h
  84.         ENDM
  85. ENDIF
  86.  
  87. ovlflgrec    RECORD    locked:1=0,ems:1=0,loaded:1=0 ; overlay flags
  88.  
  89. ; This is a dirty hack. What we need is a virtual segment that will be built
  90. ; by the (our) loader in multiple copies, one per overlay. Unfortunately, this
  91. ; doesn't seem to be a sensible idea in the minds of the folks at Microsoft.
  92. ; Declaring this segment AT will ensure that it never appears in the exefile,
  93. ; and ASSUME is dumb enough to be fooled.
  94. ;
  95. ; The reason we want to do this is also not-to-be-tried-at-home: it turns out
  96. ; that we can code a faster interrupt handler if we map overlay numbers to
  97. ; segment values. Normally we would consider this unacceptable programming
  98. ; practise because it is 86-mode specific, but the *need* for this entire
  99. ; programme is 86-mode specific, anyway.
  100.  
  101. pspseg        SEGMENT PARA AT FAERIE        ; dummy segment for psp
  102.         ORG    2ch            ; ^ to segment of environmemt in psp
  103. pspenv        LABEL    WORD
  104. pspseg        ENDS
  105.  
  106. ovltbl        SEGMENT PARA AT FAERIE        ; Dummy segment definition for overlay table
  107.  
  108. ; NOTE: This segment definition MUST be exactly 16 bytes long
  109.  
  110. ovlflg        ovlflgrec    <0,0,0>     ; overlay flags
  111. ovlinvcnt    DB    ?            ; invocation count
  112. ovlmemblk    DW    ?            ; ^ to allocated memory block
  113. ovllrudat    DD    ?            ; misc lru data (pseudo time stamp)
  114. ovlemshdl    DW    ?            ; ovl ems memory handle
  115. ovlfiloff    DW    ?            ; ovl file offset in pages (512 bytes)
  116. ovlsiz        DW    ?            ; ovl size in paragraphs
  117. ovlhdrsiz    DW    ?            ; hdr size in paragraphs
  118.  
  119. IF1
  120. IF        ($ - ovlflg) GT PARSIZ
  121.         .ERR
  122.         %OUT This segment MUST be no more than 16 bytes, REALLY!!!
  123. ENDIF
  124. ENDIF
  125.  
  126. OVLSEGSIZ    EQU    PARSIZ            ; this had better be true!!! (16 bytes)
  127.  
  128. ovltbl        ENDS
  129.  
  130. EXEHDR        STRUC                ; structure of an EXE header
  131. exesign     DW    5a4dh            ; signature
  132. exelstpgesiz    DW    ?            ; last page size (512 byte pages)
  133. exesiz        DW    ?            ; total pages (including partial last page)
  134. relocitems    DW    ?            ; number of relocation entries
  135. hdrparas    DW    ?            ; number of paragraphs in the header
  136. minalloc    DW    ?            ; minimum paragraph allocation
  137. maxalloc    DW    ?            ; maximum patagraph allocation
  138. exess        DW    ?            ; initial stack segment
  139. exesp        DW    ?            ; initial stack pointer
  140. exechksum    DW    ?            ; checksum
  141. exeip        DW    ?            ; initial instruction pointer
  142. execs        DW    ?            ; initial code segment
  143. reloctbloff    DW    ?            ; offset from beginning of header to relocation table
  144. exeovlnum    DW    ?            ; overlay number
  145. EXEHDR        ENDS
  146.  
  147. MASK_used    EQU    1            ; memory block flag
  148.  
  149. MEMCTLBLK    STRUC                ; memory block structure
  150. memblkflg    DB    ?            ; flags
  151. memblkpad1    DB    ?            ; go ahead, delete me!
  152. memblknxt    DW    ?            ; ^ to next block
  153. memblkprv    DW    ?            ; ^ to previous block
  154. memblkovl    DW    ?            ; ^ to overlay occupying this block
  155. memblksiz    DW    ?            ; size in paragraphs
  156. memblkpad    DB    PARSIZ - memblkpad MOD PARSIZ DUP (?) ; pad to 16 bytes
  157. MEMCTLBLK    ENDS
  158.  
  159. MEMCTLBLKSIZ    EQU    TYPE MEMCTLBLK / PARSIZ ; should equal 1 paragraph
  160.  
  161. ;-------------------------------------------------------------------------------
  162.  
  163. code        SEGMENT PUBLIC
  164.  
  165. ; NOTE: the following order is optimum for alignment purposes across the
  166. ;    entire INTEL 80x86 family of processors.
  167.  
  168. ovltim        DD    ?            ; pseudo-lru time variable
  169. farcall     DD    ?            ; internal trampoline.
  170. oldvec        DD    -1            ; saved interrupt vector
  171. oldint21    DD    -1            ; saved int 21 vector
  172. sireg        DW    ?            ; temp save area
  173. IFDEF i386
  174.         DW    ?            ; for esi
  175. ENDIF
  176. dsreg        DW    ?            ; temp save area
  177. ssreg        DW    ?
  178. spreg        DW    ?
  179. ovlexefilhdl    DW    -1            ; always-open file handle of our .EXE
  180. ovltblbse    DW    -1            ; segment of first overlay descriptor
  181. memblks     DW    16 DUP (-1)        ; allocated memory blocks
  182. memblk1st    DW    ?            ; first memory block
  183. emsmemblks    DW    16 DUP (-1)        ; ems allocated memory blocks (64K each)
  184. curemshandle    DW    -1            ; currently mapped handle
  185. ovlcnt        DW    ?            ; # overlays
  186. modcnt        DW    ?            ; # of modules
  187. ovlrootcode    DW    ?            ; logical segment of OVERLAY_AREA
  188. ovldata     DW    ?            ; logical segment of OVERLAY_END
  189. pspadd        DW    ?            ; our psp address + 10h (for relocations)
  190. emsframe    DW    ?            ; EMM page frame segment
  191. moduletbl    DD    256 DUP (?)        ; module lookup table (256 modules)
  192. curovl        DW    OFFSET stkframe     ; ^ into stack frame
  193. stkframe    DW    256*3 DUP (?)        ; internal stack (256 ovls deep)
  194. tempmem     DW    16 DUP (-1)        ; temp mem block storage
  195. intnum        DW    ?            ; ovlmgr int number
  196. hdr        EXEHDR    <>            ; EXE header work area
  197.         DB    512-TYPE EXEHDR DUP (?) ; exe hdr buffer for relocations
  198. EXEHDRTMPSIZ    EQU    $ - hdr         ; size of temp reloc buffer
  199. errortbl    DW    -1            ; error message pointers
  200.         DW    OFFSET baddos
  201.         DW    OFFSET nofile
  202.         DW    OFFSET noroom
  203.         DW    OFFSET nofile
  204.         DW    OFFSET nocore
  205.         DW    OFFSET nocore
  206.         DW    OFFSET badems
  207.         DW    OFFSET nofile
  208.         DW    OFFSET unknown
  209.         DW    OFFSET unknown
  210.         DW    OFFSET unknown
  211.         DW    OFFSET unknown
  212.         DW    OFFSET unknown
  213.         DW    OFFSET unknown
  214.         DW    OFFSET unknown
  215. emmname     DB    "EMMXXXX0"              ; EMM device driver name
  216. emmtot        DW    0            ; total emm blocks free
  217. emmframesiz    DW    4            ; frame size in blocks
  218. emmflg        DB    0            ; EMM present flag
  219.  
  220. i386code    DB    '386 specific code enabled.',CR,LF,'$'
  221. memavl        DB    'Conventional memory available: $'
  222. paragraphs    DB    'H paragraphs.',CR,LF,'$'
  223. emsavl        DB    'EMS memory available: $'
  224. pages        DB    'H 16K-pages.',CR,LF,'$'
  225. noroom        DB    'Not enough free memory left to run this program.$'
  226. nocore        DB    'Internal memory allocation failure.$'
  227. nofile        DB    'Inaccessible EXE file. Can',27,'t load overlays.$'
  228. baddos        DB    'Incorrect DOS version. Must be 3.00 or later.$'
  229. badems        DB    'EMS memory manager error.$'
  230. unknown     DB    'Unknown error!$'
  231. msghead     DB    ESCAPE,'[0m',ESCAPE,'[K',CR,LF,ESCAPE,'[K',ESCAPE,'[1mOVLMGR:',ESCAPE,'[0m $'
  232. diag        DB    ESCAPE,'[K',CR,LF,ESCAPE,'[K','        ($'
  233. msgtail     DB    ESCAPE,'[K',CR,LF,ESCAPE,'[K',BELL,'$'
  234.  
  235. ;-------------------------------------------------------------------------------
  236.  
  237. $$OVLINIT    PROC    FAR            ; Init entry point
  238.  
  239.         ASSUME    CS:code,DS:pspseg,ES:NOTHING
  240.  
  241.         push    ax
  242.         push    bx
  243.         push    cx
  244.         push    dx
  245.         push    si
  246.         push    di
  247.         push    bp
  248.         push    ds
  249.         push    es            ; save the world
  250.         cld
  251.         mov    ax,ds            ; get our psp
  252.         add    ax,10h
  253.         mov    pspadd,ax        ; save it
  254.         mov    ah,DOSVERSION
  255.         int    DOS
  256.         cmp    al,3            ; DOS 3.0 or later
  257.         jnc    doenvthing
  258.         mov    al,DOSERR        ; incorrect version of dos
  259.         jmp    putserr
  260. doenvthing:
  261.         mov    ds,pspenv        ; get environment segment
  262.         mov    si,-1
  263. envloop:                    ; search for end of environment
  264.         inc    si
  265.         cmp    WORD PTR [si],0
  266.         jnz    envloop
  267.         add    si,4            ; point to EXE filename
  268.         mov    al,0            ; access code
  269.         mov    ah,DOSOPEN
  270.         mov    dx,si
  271.         int    DOS            ; open EXE
  272.         jnc    dontdie
  273.         mov    al,FILEERR        ; can't open file!
  274.         jmp    putserr
  275. dontdie:
  276.         mov    ovlexefilhdl,ax     ; save handle
  277. IFNDEF NOEMS
  278. chkems:
  279.         mov    ah,DOSGETVEC
  280.         mov    al,EMM
  281.         int    DOS
  282.         mov    ax,cs
  283.         mov    ds,ax
  284.         mov    di,0ah
  285.         mov    si,OFFSET emmname
  286.         mov    cx,8
  287.         repe    cmpsb
  288.         mov    al,0
  289.         jnz    setemmflg
  290.         mov    al,-1
  291. setemmflg:
  292.         mov    emmflg,al
  293.         jnz    noemshere
  294.         mov    ah,EMMFRAME
  295.         int    EMM
  296.         mov    emsframe,bx
  297.         mov    ah,EMMTOTALS
  298.         int    EMM
  299.         mov    emmtot,bx
  300. noemshere:
  301. ENDIF
  302.         mov    ax,SEG $$OVLBASE    ; OVERLAY_AREA segment
  303.         mov    ovlrootcode,ax
  304.         mov    ax,SEG $$COVL        ; segment of DGROUP
  305.         mov    ds,ax
  306.         mov    bx,$$CGSN        ; number of modules
  307.         mov    modcnt,bx        ; save for later use
  308.         mov    bx,$$COVL        ; number of physical overlays
  309.         mov    ovlcnt,bx        ; save for later use
  310.  
  311. ; Now allocate memory
  312.         mov    ah,DOSALLOC        ; bx contains # paras needed for ovltbl
  313.         int    DOS
  314.         jnc    gotovlram
  315.         jmp    buyram
  316. gotovlram:
  317.         mov    ovltblbse,ax        ; overlay descriptor table begins at start of memory block
  318.  
  319.         push    cs
  320.         pop    ds
  321. IFDEF DEBUG
  322. IFDEF i386
  323.         mov    ah,print
  324.         mov    dx,OFFSET msghead
  325.         int    DOS
  326.         mov    ah,print
  327.         mov    dx,OFFSET i386code
  328.         int    DOS
  329. ENDIF
  330.         mov    ah,print
  331.         mov    dx,OFFSET msghead
  332.         int    DOS
  333.         mov    ah,print
  334.         mov    dx,OFFSET memavl
  335.         int    DOS
  336.         mov    ax,0a000h
  337.         sub    ax,ovltblbse
  338.         call    itoa
  339.         mov    ah,print
  340.         mov    dx,OFFSET paragraphs
  341.         int    DOS
  342. IFNDEF NOEMS
  343.         mov    ah,print
  344.         mov    dx,OFFSET msghead
  345.         int    DOS
  346.         mov    ah,print
  347.         mov    dx,OFFSET emsavl
  348.         int    DOS
  349.         mov    ax,emmtot
  350.         call    itoa
  351.         mov    ah,print
  352.         mov    dx,OFFSET pages
  353.         int    DOS
  354. ENDIF
  355. ENDIF
  356.         ASSUME    ES:ovltbl
  357.  
  358.         xor    bp,bp
  359.         xor    di,di
  360.         xor    si,si
  361. filsegtbllpp:                    ; initialise ovl table
  362.         call    gethdr            ; get an EXE header
  363.         mov    ax,ovltblbse
  364.         add    ax,hdr.exeovlnum
  365.         mov    es,ax            ; ^ to ovl table entry
  366.         xor    ax,ax
  367.         mov    WORD PTR ovllrudat,ax    ; initialise ovl lru
  368.         mov    WORD PTR ovllrudat+2,ax
  369.         mov    ovlflg,al        ; initialise ovl flags
  370.         mov    ovlinvcnt,al        ; initialise invocation count
  371.         mov    ovlemshdl,-1
  372.         mov    ax,hdr.exesiz
  373.         shl    ax,1
  374.         shl    ax,1
  375.         shl    ax,1
  376.         shl    ax,1
  377.         shl    ax,1            ; * 32
  378.         mov    dx,hdr.exelstpgesiz
  379.         or    dx,dx
  380.         jz    emptypage
  381.         shr    dx,1
  382.         shr    dx,1
  383.         shr    dx,1
  384.         shr    dx,1            ; / 16
  385.         inc    dx
  386.         sub    ax,20h
  387.         add    ax,dx
  388. emptypage:
  389.         sub    ax,hdr.hdrparas     ; actual size of code
  390.         mov    ovlsiz,ax        ; overlay size in paragraphs
  391.         cmp    hdr.exeovlnum,0     ; skip if ovl 0 (root code)
  392.         jz    notlargest
  393.         cmp    ax,di            ; find largest ovl
  394.         jc    notlargest
  395.         mov    di,ax
  396. notlargest:
  397.         mov    ax,hdr.hdrparas
  398.         shl    ax,1
  399.         shl    ax,1
  400.         shl    ax,1
  401.         shl    ax,1
  402.         mov    ovlhdrsiz,ax        ; hdr size in bytes
  403.         mov    ovlfiloff,bp        ; initialise ovl file offset
  404.         add    bp,hdr.exesiz        ; ^ to next overlay
  405.         mov    dx,bp
  406.         mov    cl,dh
  407.         mov    dh,dl
  408.         xor    ch,ch
  409.         xor    dl,dl
  410.         shl    dx,1
  411.         rcl    cx,1            ; cx:dx = bp * 512
  412.         mov    al,0
  413.         mov    ah,DOSSEEK        ; seek to next ovl
  414.         int    DOS
  415.         mov    ax,ovlcnt
  416.         dec    ax
  417.         cmp    ax,hdr.exeovlnum    ; all overlays done?
  418.         jz    makmemblk
  419.         jmp    filsegtbllpp        ; Nope, go for more.
  420. makmemblk:
  421.         ASSUME    ES:nothing        ; prepare first memory block
  422.  
  423.         mov    ax,ovlrootcode        ; OVERLAY_AREA segment
  424.         mov    memblk1st,ax        ; save pointer to first mem block
  425.         mov    es,ax
  426.         mov    es:memblkflg,0        ; clear mem flags
  427.         mov    es:memblknxt,0        ; set next to nothing
  428.         mov    es:memblkprv,0        ; set previous to nothing
  429.         mov    es:memblkovl,0        ; no overlay loaded
  430.         mov    es:memblksiz,di     ; di contains OVERLAY_AREA size in paragraphs
  431.         add    ax,di
  432.         mov    ovldata,ax        ; end of OVERLAY_END
  433.         push    di
  434.         mov    es,ovltblbse        ; temporary
  435.         call    getemsmem        ; see if any ems available
  436.         mov    es:ovlemshdl,-1     ; fix these!
  437.         and    es:ovlflg,NOT MASK ems
  438.         push    dx
  439.         call    getmoreram        ; see if there are any other pieces lying around
  440.         pop    ax
  441.         pop    di
  442.         or    ax,ax            ; any ems?
  443.         jnz    noramcheck
  444.         inc    di
  445.         cmp    dx,di
  446.         jc    buyram
  447. noramcheck:
  448.         mov    WORD PTR ovltim,0    ; initialise global lru time stamp
  449.         mov    WORD PTR ovltim+2,0
  450.         mov    di,OFFSET stkframe
  451.         mov    WORD PTR cs:[di],-1    ; initialise stack frame
  452.         add    di,6
  453.         mov    ax,ovltblbse
  454.         mov    cs:[di],ax
  455.         mov    curovl,di        ; initialise stack frame pointer
  456.         mov    es,ax
  457.         mov    es:ovlflg,MASK locked OR MASK loaded ; set flags on ovl 0
  458.         jmp    short chgintvec
  459. buyram:
  460.         mov    al,NOMEMERR        ; free up some TSRs or something
  461.         jmp    putserr
  462. chgintvec:
  463.         mov    ax,SEG $$INTNO
  464.         mov    ds,ax
  465.         mov    al,$$INTNO        ; get int number to use
  466.         xor    ah,ah
  467.         shl    ax,1
  468.         shl    ax,1
  469.         mov    intnum,ax
  470.         call    setvectors        ; set up interrupt vectors
  471.         mov    cx,modcnt        ; module count
  472.         mov    ax,SEG $$MPGSNBASE
  473.         mov    es,ax
  474.         mov    ax,cs
  475.         mov    ds,ax
  476.  
  477.         ASSUME    DS:code
  478.  
  479.         mov    bx,OFFSET $$MPGSNBASE    ; ^ to linker provided overlay segment fixups
  480.         mov    si,OFFSET $$MPGSNOVL    ; ^ to linker provided module table
  481.         mov    di,OFFSET moduletbl    ; ^ to our module table
  482. modloop:
  483.         mov    al,es:[si]        ; real physical ovl number
  484.         xor    ah,ah
  485.         add    ax,ovltblbse        ; ovlctlseg address
  486.         mov    [di],ax         ; save in module table
  487.         mov    ax,es:[bx]        ; get seg fixup
  488.         sub    ax,ovlrootcode        ; adjust for relative reference
  489.         mov    [di+2],ax        ; save in module table
  490.         add    di,4
  491.         add    bx,2
  492.         inc    si
  493.         loop    modloop
  494.         pop    es
  495.         pop    ds
  496.         pop    bp
  497.         pop    di
  498.         pop    si
  499.         pop    dx
  500.         pop    cx
  501.         pop    bx
  502.         pop    ax            ; restore the world
  503.         jmp    $$MAIN            ; And away we go!
  504.  
  505. $$OVLINIT    ENDP
  506.  
  507. ;-------------------------------------------------------------------------------
  508.  
  509. ovlmgr        PROC    FAR            ; This is the it!
  510.  
  511.         ASSUME    DS:NOTHING,ES:NOTHING
  512.  
  513. IFDEF i386
  514.         OP32
  515. ENDIF
  516.         mov    sireg,si        ; preserve si
  517.         mov    dsreg,ds        ; and ds
  518.         pop    si            ; retrieve caller ip
  519.         pop    ds            ;     "      "    cs
  520.         push    ax
  521.         push    bx
  522.         cld
  523.         lodsb                ; module # to call
  524.         xor    ah,ah
  525.         mov    bx,ax
  526.         lodsw                ; offset in ovl to call
  527.         mov    WORD PTR farcall,ax    ; into trampoline
  528.         mov    ax,si
  529.         mov    si,curovl        ; get stack frame pointer
  530.         add    si,6            ; update stack
  531.         mov    cs:[si-4],ds        ; save return seg
  532.         mov    cs:[si-2],ax        ; and return offset
  533.  
  534.         shl    bx,1
  535.         shl    bx,1            ; * 4 (2 words/entry in module tbl)
  536.         add    bx,OFFSET moduletbl
  537.         mov    ds,cs:[bx]        ; ovl tbl entry
  538.         mov    ax,cs:[bx+2]        ; segment fixup
  539.         mov    cs:[si],ds        ; ovl entry into stack frame
  540.         mov    curovl,si
  541.  
  542.         ASSUME    DS:ovltbl
  543.  
  544. IFDEF i386
  545.         OP32
  546. ENDIF
  547.         mov    si,WORD PTR ovltim    ; lru time stamp
  548. IFDEF i386
  549.         OP32
  550. ENDIF
  551.         inc    si            ; time passes!
  552. IFDEF i386
  553.         OP32
  554. ENDIF
  555.         mov    WORD PTR ovltim,si    ; update global clock
  556. IFDEF i386
  557.         OP32
  558. ENDIF
  559.         mov    WORD PTR ovllrudat,si    ; as well as ovl clock
  560. IFNDEF i386
  561.         mov    si,WORD PTR ovltim+2
  562.         jz    ininc            ; dword increment
  563. cryupcdon:
  564.         mov    WORD PTR ovllrudat+2,si ; as well as ovl clock
  565. ENDIF
  566.         test    ovlflg,MASK loaded    ; ovl loaded?
  567.         jz    inload            ; load it or map it then.
  568. ovlloadedupc:
  569.         inc    ovlinvcnt
  570.         add    ax,ovlmemblk        ; add fixup and segment address
  571.         mov    WORD PTR farcall+2,ax    ; into trampoline
  572. IFDEF i386
  573.         OP32
  574. ENDIF
  575.         mov    si,sireg        ; retore all registers
  576.         mov    ds,dsreg
  577.         pop    bx
  578.         pop    ax
  579.         popf                ; don't forget these!
  580.         call    DWORD PTR farcall    ; and GO
  581.         pushf                ; preserve registers again!
  582.         mov    dsreg,ds
  583. IFDEF i386
  584.         OP32
  585. ENDIF
  586.         mov    sireg,si
  587.         mov    si,curovl        ; stack frame pointer
  588.         mov    ds,cs:[si]
  589.         dec    ovlinvcnt
  590.         sub    si,6            ; adjust stack
  591.         mov    ds,cs:[si]        ; retrieve ovl tbl entry
  592.         push    cs:[si+2]        ; set return address
  593.         push    cs:[si+4]
  594.         mov    curovl,si
  595. IFDEF i386
  596.         OP32
  597. ENDIF
  598.         mov    si,WORD PTR ovltim    ; do the lru thing again
  599. IFDEF i386
  600.         OP32
  601. ENDIF
  602.         inc    si
  603. IFDEF i386
  604.         OP32
  605. ENDIF
  606.         mov    WORD PTR ovltim,si
  607. IFDEF i386
  608.         OP32
  609. ENDIF
  610.         mov    WORD PTR ovllrudat,si
  611. IFNDEF i386
  612.         mov    si,WORD PTR ovltim+2
  613.         jz    outinc
  614. crydncdon:
  615.         mov    WORD PTR ovllrudat+2,si
  616. ENDIF
  617.         test    ovlflg,MASK loaded    ; ovl loaded?
  618.         jz    outload         ; better get it before someone notices
  619. jmpback:
  620. IFDEF i386
  621.         OP32
  622. ENDIF
  623.         mov    si,sireg        ; get registers back
  624.         mov    ds,dsreg
  625.         iret                ; and GO back
  626.  
  627. IFNDEF i386
  628. ininc:
  629.         inc    si
  630.         mov    WORD PTR ovltim+2,si    ; update global and
  631.         jmp    cryupcdon
  632. ENDIF
  633.  
  634. inload:
  635.         test    ovlflg,MASK ems
  636.         jz    infile
  637.         push    ax
  638.         mov    ax,ovlemshdl
  639.         call    mappage
  640.         pop    ax
  641.         jmp    ovlloadedupc
  642. infile:
  643.         call    loadoverlay        ; self explanatory
  644.         jmp    ovlloadedupc
  645.  
  646. IFNDEF i386
  647. outinc:
  648.         inc    si
  649.         mov    WORD PTR ovltim+2,si
  650.         jmp    crydncdon
  651. ENDIF
  652.  
  653. outload:
  654.         test    ovlflg,MASK ems
  655.         jz    outfile
  656.         push    ax
  657.         mov    ax,ovlemshdl
  658.         call    mappage
  659.         pop    ax
  660.         jmp    jmpback
  661. outfile:
  662.         call    loadoverlay
  663.         jmp    jmpback
  664.  
  665. ovlmgr        ENDP
  666.  
  667. ;-------------------------------------------------------------------------------
  668.  
  669. loadoverlay    PROC    NEAR            ; load overlay pointed to by es
  670.  
  671.         ASSUME    DS:NOTHING,ES:ovltbl
  672.  
  673. IFDEF i386
  674.         OP32
  675.         pusha                   ; eax,ecx,edx,ebx,esp,ebp,esi,edi
  676. ELSE
  677.         push    ax
  678.         push    cx
  679.         push    dx
  680.         push    bx
  681.         push    bp
  682.         push    si
  683.         push    di
  684. ENDIF
  685.         push    ds
  686.         push    es            ; just in case
  687.         mov    ax,ds
  688.         mov    es,ax
  689.         cmp    ovlinvcnt,0
  690.         jnz    fxdadr            ; Yup, it's a toughie
  691.         mov    ax,ovlsiz        ; How much?
  692.         call    getpages        ; never fail mem alloc, you bet.
  693.         jmp    gleaner
  694. fxdadr:
  695.         call    releasepages        ; free memory where this ovl should be loaded
  696. gleaner:
  697.         add    ax,MEMCTLBLKSIZ     ; skip mem ctl blk
  698.         mov    ovlmemblk,ax        ; memory block to use
  699.         mov    ds,ax
  700.         mov    dx,ovlfiloff        ; where in the file is it?
  701.         mov    cl,dh
  702.         mov    dh,dl
  703.         xor    ch,ch
  704.         xor    dl,dl
  705.         shl    dx,1
  706.         rcl    cx,1            ; cx:dx = dx * 512
  707.         mov    ax,ovlhdrsiz
  708.         push    cx
  709.         push    dx
  710.         add    dx,ax
  711.         adc    cx,0            ; position to code
  712.         mov    ah,DOSSEEK        ; lseek to code
  713.         mov    al,0            ; from beginning of file
  714.         mov    bx,ovlexefilhdl     ; never closing handle
  715.         int    DOS
  716.         jc    burnhead        ; oops!
  717.         xor    dx,dx            ; buf = ds:0
  718.         mov    cx,ovlsiz        ; number of paragraphs to load
  719.         shl    cx,1
  720.         shl    cx,1
  721.         shl    cx,1
  722.         shl    cx,1            ; * 16 = number of bytes
  723.         mov    ah,DOSREAD        ; prevent random DOS behaviour
  724.         int    DOS            ; read in code
  725.         jc    burnhead        ; double oops!
  726.         pop    dx
  727.         pop    cx            ; position of hdr
  728.         mov    ah,DOSSEEK        ; lseek to hdr
  729.         mov    al,0            ; from beginning of file
  730.         mov    bx,ovlexefilhdl     ; never closing handle
  731.         int    DOS
  732.         jc    burnhead        ; oops!
  733.         mov    cx,EXEHDRTMPSIZ     ; reloc buffer size
  734.         mov    dx,OFFSET hdr
  735.         push    ds
  736.         mov    ax,cs
  737.         mov    ds,ax
  738.         mov    ah,DOSREAD        ; prevent random DOS behaviour
  739.         int    DOS            ; read in header
  740.         pop    ds
  741.         jc    burnhead        ; double oops!
  742.  
  743.         call    ovlrlc            ; perform relocation normally done by DOS EXE loader
  744.         pop    es            ; retrieve ovl tbl entry
  745.         pop    ds
  746.  
  747.         ASSUME    DS:ovltbl,ES:NOTHING
  748.  
  749.         or    ovlflg,MASK loaded    ; because it is now
  750. IFDEF i386
  751.         OP32
  752.         popa
  753. ELSE
  754.         pop    di
  755.         pop    si
  756.         pop    bp
  757.         pop    bx
  758.         pop    dx
  759.         pop    cx
  760.         pop    ax
  761. ENDIF
  762.         ret
  763.  
  764. burnhead:
  765.         mov    al,FILEIOERR        ; some kind of I/O error
  766.         jmp    putserr
  767.  
  768. loadoverlay    ENDP
  769.  
  770. ;-------------------------------------------------------------------------------
  771.  
  772. ovlrlc        PROC    NEAR            ; ds:0 -> the overlay to relocate
  773.  
  774.         ASSUME    DS:NOTHING,ES:NOTHING
  775.  
  776.         mov    si,OFFSET hdr
  777.         mov    bp,si
  778.         add    bp,EXEHDRTMPSIZ     ; ^ to end of buf+1
  779.         mov    cx,cs:[si.relocitems]    ; roto-count
  780.         jcxz    relocdone        ; not such a good idea, after all
  781.         mov    di,ds
  782.         sub    di,ovlrootcode        ; segment fixup value
  783.         add    si,cs:[si.reloctbloff]    ; ^ relocation table
  784. dorelocs:                    ; labels don't GET comments
  785.         cmp    si,bp            ; past the end ?
  786.         jc    getoffsetl
  787.         call    getnxtreloc        ; get another hunk
  788. getoffsetl:
  789.         mov    bl,cs:[si]        ; offset into load module
  790.         inc    si
  791.         cmp    si,bp            ; past the end ?
  792.         jc    getoffseth
  793.         call    getnxtreloc        ; get another hunk
  794. getoffseth:
  795.         mov    bh,cs:[si]        ; offset into load module
  796.         inc    si
  797.         cmp    si,bp            ; past the end ?
  798.         jc    getsegmentl
  799.         call    getnxtreloc        ; get another hunk
  800. getsegmentl:
  801.         mov    al,cs:[si]        ; segment in load module (zero reference)
  802.         inc    si
  803.         cmp    si,bp            ; past the end ?
  804.         jc    getsegmenth
  805.         call    getnxtreloc        ; get another hunk
  806. getsegmenth:
  807.         mov    ah,cs:[si]        ; segment in load module (zero reference)
  808.         inc    si
  809.         add    ax,pspadd        ; now it is psp relative
  810.         add    ax,di            ; and now it is relative to the actual load address
  811.         mov    es,ax
  812.         mov    ax,es:[bx]        ; pickup item to relocate
  813.         add    ax,pspadd        ; make it psp relative
  814.         cmp    ax,ovlrootcode        ; is it below the OVERLAY_AREA?
  815.         jc    reloccomputed        ; yup. it's relocated
  816.         cmp    ax,ovldata        ; is it above OVERLAY_AREA
  817.         jnc    reloccomputed        ; yup. it's relocated
  818.         add    ax,di            ; it's in OVERLAY_AREA, this one's ours.
  819. reloccomputed:
  820.         mov    es:[bx],ax        ; RAM it home!?!
  821.         loop    dorelocs        ; what goes around, comes around.
  822. relocdone:    ret
  823.  
  824. ovlrlc        ENDP
  825.  
  826. ;-------------------------------------------------------------------------------
  827.  
  828. getnxtreloc    PROC    NEAR
  829.  
  830.         ASSUME    DS:NOTHING,ES:NOTHING
  831.  
  832.         push    bx
  833.         push    cx
  834.         push    di
  835.         push    bp
  836.         push    ds
  837.         push    es
  838.         mov    cx,EXEHDRTMPSIZ     ; reloc buffer size
  839.         mov    dx,OFFSET hdr
  840.         mov    ax,cs
  841.         mov    ds,ax
  842.         mov    bx,ovlexefilhdl     ; never closing handle
  843.         mov    ah,DOSREAD        ; prevent random DOS behaviour
  844.         int    DOS            ; read in header
  845.         jnc    nxtrelocok
  846.         jmp    burnhead        ; double oops!
  847. nxtrelocok:
  848.         mov    si,OFFSET hdr
  849.         pop    es
  850.         pop    ds
  851.         pop    bp
  852.         pop    di
  853.         pop    cx
  854.         pop    bx
  855.         ret
  856.  
  857. getnxtreloc    ENDP
  858.  
  859. ;-------------------------------------------------------------------------------
  860.  
  861. getvictim    PROC    NEAR            ; select a victim to discard (and free up some memory)
  862.  
  863.         ASSUME    DS:ovltbl,ES:NOTHING
  864.  
  865.         push    bx
  866.         push    cx
  867.         push    dx
  868.         push    si
  869.         push    di
  870.         push    bp
  871.         push    ds
  872.         mov    ds,ovltblbse        ; ^ ovl tbl
  873. IFDEF i386
  874.         OP32
  875. ENDIF
  876.         xor    ax,ax            ; will contain the low word of lru
  877. IFDEF i386
  878.         OP32
  879. ENDIF
  880.         mov    dx,ax            ; will contain the high word of lru
  881.         mov    bp,ax            ; will contain ovl tbl entry
  882.         mov    bx,ax            ; ovl tbl ptr
  883.         mov    cx,ovlcnt
  884. foon1:
  885.         test    ovlflg[bx],MASK locked
  886.         jnz    skip1
  887.         test    ovlflg[bx],MASK ems
  888.         jnz    foon2
  889.         test    ovlflg[bx],MASK loaded
  890.         jz    skip1
  891. foon2:
  892. IFDEF i386
  893.         OP32
  894. ENDIF
  895.         mov    si,WORD PTR ovltim
  896. IFNDEF i386
  897.         mov    di,WORD PTR ovltim+2
  898. ENDIF
  899. IFDEF i386
  900.         OP32
  901. ENDIF
  902.         sub    si,WORD PTR ovllrudat[bx]
  903. IFNDEF i386
  904.         sbb    di,WORD PTR ovllrudat[bx+2]
  905. ENDIF
  906. IFDEF i386
  907.         OP32
  908.         cmp    dx,si
  909. ELSE
  910.         cmp    dx,di
  911. ENDIF
  912. IFDEF i386
  913.         jnc    skip1
  914. ELSE
  915.         jc    better1
  916.         jnz    skip1
  917.         cmp    ax,si
  918.         jnc    skip1
  919. ENDIF
  920. better1:
  921. IFDEF i386
  922.         OP32
  923.         mov    dx,si
  924. ELSE
  925.         mov    ax,si
  926.         mov    dx,di
  927. ENDIF
  928.         mov    bp,bx
  929. skip1:
  930.         add    bx,OVLSEGSIZ
  931.         loop    foon1
  932.         or    bp,bp            ; were we more successful this time?
  933.         jnz    gotvictim        ; now we got one.
  934. nomoremem:
  935.         mov    al,VICTIMERR        ; were really %$# now!
  936.         jmp    putserr
  937. gotvictim:
  938.         shr    bp,1            ; convert offset to segment
  939.         shr    bp,1
  940.         shr    bp,1
  941.         shr    bp,1
  942.         mov    ax,ds
  943.         add    ax,bp
  944.         pop    ds
  945.         pop    bp
  946.         pop    di
  947.         pop    si
  948.         pop    dx
  949.         pop    cx
  950.         pop    bx
  951.         ret
  952.  
  953. getvictim    ENDP
  954.  
  955. ;-------------------------------------------------------------------------------
  956.  
  957. int21        PROC    FAR
  958.  
  959. ; free almost all overlay memory if app. tries to call the DOS exec function.
  960.  
  961.         cmp    ah,DOSEXEC
  962.         jz    freeall
  963.         cmp    ah,TERMINATE
  964.         jz    saybyebye
  965. notours:
  966.         jmp    cs:oldint21
  967. saybyebye:
  968.         mov    al,NOERR        ; return code 0
  969.         jmp    putserr
  970. freeall:
  971.         or    al,al            ; is it load and exec?
  972.         jnz    notours
  973.         push    ax
  974.         push    cx
  975.         push    dx
  976.         push    bx
  977.         push    bp
  978.         push    si
  979.         push    di
  980.         push    es
  981.         push    ds            ; preserve calling env.
  982.  
  983.         ASSUME    DS:NOTHING,ES:ovltbl
  984.  
  985.         mov    es,ovltblbse
  986.         mov    cx,ovlcnt        ; unload all overlays that are
  987.         mov    bx,OVLSEGSIZ        ; in EMS or are in alloced mem.
  988.         dec    cx
  989. memunloadlp:
  990.         test    [bx.ovlflg],MASK ems
  991.         jnz    memunload
  992.         test    [bx.ovlflg],MASK loaded
  993.         jz    nxtmemunload
  994.         mov    ax,[bx.ovlmemblk]
  995.         sub    ax,MEMCTLBLKSIZ
  996.         cmp    ax,memblks        ; allocated memory ?
  997.         jc    nxtmemunload
  998. memunload:
  999.         and    [bx.ovlflg],NOT MASK loaded ; you're outta there!
  1000. nxtmemunload:
  1001.         add    bx,OVLSEGSIZ
  1002.         loop    memunloadlp
  1003.  
  1004.         mov    curemshandle,-1     ; no current handle anymore
  1005.  
  1006.         mov    ax,memblks
  1007.         cmp    ax,-1
  1008.         jz    nosecondblk
  1009.         mov    es,ax            ; ^ to second mem blk
  1010.         mov    es,es:memblkprv     ; get previous pointer
  1011.         mov    es:memblknxt,0        ; no other blocks after this one
  1012. nosecondblk:
  1013.         mov    cx,16            ; do all allocated mem blocks
  1014.         mov    si,OFFSET memblks
  1015. freememblklp:
  1016.         mov    ax,cs:[si]        ; get memory blk segment
  1017.         cmp    ax,-1            ; was one ever allocated?
  1018.         jz    nxtmemblklp        ; nope
  1019.         mov    es,ax
  1020.         mov    ah,DOSFREE        ; must free it.
  1021.         int    DOS
  1022.         mov    WORD PTR cs:[si],-1
  1023. nxtmemblklp:
  1024.         add    si,2
  1025.         loop    freememblklp
  1026.  
  1027.         call    rstvectors        ; restore all int vectors
  1028.  
  1029.         mov    bp,sp
  1030.         push    [bp+22]         ; ensure returned flags are based on user's!
  1031.         popf
  1032.         pop    ds
  1033.         pop    es
  1034.         pop    di
  1035.         pop    si
  1036.         pop    bp
  1037.         pop    bx
  1038.         pop    dx
  1039.         pop    cx
  1040.         pop    ax
  1041.  
  1042.         mov    ssreg,ss        ; preserve these due to a
  1043.         mov    spreg,sp        ; DOS bug.
  1044.  
  1045.         int    DOS            ; allow DOS to continue!
  1046.  
  1047.         mov    ss,ssreg
  1048.         mov    sp,spreg
  1049.  
  1050.         push    ax
  1051.         push    cx
  1052.         push    dx
  1053.         push    bx
  1054.         push    bp
  1055.         push    si
  1056.         push    di
  1057.         push    es
  1058.         push    ds            ; preserve calling env.
  1059.         mov    bp,sp
  1060.         pushf
  1061.         pop    [bp+22]         ; fix return flags
  1062.  
  1063.         call    getmoreram        ; re-allocate our memory
  1064.         call    setvectors        ; patch vectors again
  1065.  
  1066.         pop    ds
  1067.         pop    es
  1068.         pop    di
  1069.         pop    si
  1070.         pop    bp
  1071.         pop    bx
  1072.         pop    dx
  1073.         pop    cx
  1074.         pop    ax
  1075.         iret
  1076.  
  1077. int21        ENDP
  1078.  
  1079. ;-------------------------------------------------------------------------------
  1080.  
  1081. releasepages    PROC    NEAR            ; Arg in es, result in ax
  1082.  
  1083. ; release any memory (and overlays) where this overlay should reside
  1084.  
  1085.         ASSUME    DS:NOTHING,ES:ovltbl
  1086.  
  1087.         mov    bx,ovlmemblk        ; start of memory to release
  1088.         sub    bx,MEMCTLBLKSIZ
  1089.         mov    dx,bx
  1090.         add    dx,es:ovlsiz
  1091.         add    dx,MEMCTLBLKSIZ     ; end of memory to release
  1092.         mov    ax,ovlemshdl
  1093.         cmp    ax,-1
  1094.         jz    doitagain
  1095.         call    mappage
  1096.         or    ovlflg,MASK ems
  1097.         mov    ax,emsframe
  1098.         jmp    dvart
  1099. doitagain:
  1100.         mov    ax,memblk1st        ; first memory blk
  1101.         jmp    dvart
  1102. dvartloop:
  1103.         mov    ds,ax            ; memory blk to check
  1104.         cmp    bx,ax            ; does it start below the memory to release?
  1105.         jnc    dvartsmaller        ; yup
  1106.         cmp    ax,dx            ; does it start above?
  1107.         jnc    dvartnocore        ; yup
  1108.         call    killmem         ; it's in the way. Zap it.
  1109.         jmp    dvartloop
  1110. dvartsmaller:
  1111.         add    ax,ds:memblksiz     ; end of this memory blk
  1112.         cmp    bx,ax            ; does it end below the memory to release?
  1113.         jnc    dvartsilly        ; yup
  1114.         test    ds:memblkflg,MASK_used
  1115.         jz    dvartfree
  1116.         call    killmem         ; Oh well, zap it too.
  1117.         add    ax,ds:memblksiz     ; end of this memory blk
  1118. dvartfree:
  1119.         cmp    ax,dx            ; does it end in the memory to be released?
  1120.         jc    dvartsilly
  1121. dvartgotblk:
  1122.         mov    ax,ds            ; this is it!
  1123.         mov    cx,bx
  1124.         sub    cx,ax            ; # of paragraphs between start of memory to release and mem blk
  1125.         jz    nosplit
  1126.         push    es
  1127.         call    splitblk
  1128.         or    es:memblkflg,MASK_used    ; set high block used
  1129.         call    mergemem        ; merge remaining free memory
  1130.         mov    ax,es
  1131.         mov    ds,ax
  1132.         pop    es
  1133. nosplit:
  1134.         mov    cx,es:ovlsiz
  1135.         add    cx,MEMCTLBLKSIZ     ; paragraphs needed to load ovl
  1136.         jmp    splitblklow        ; split remaining block
  1137. dvartsilly:
  1138.         mov    ax,ds:memblknxt
  1139. dvart:
  1140.         or    ax,ax            ; end of mem list?
  1141.         jz    dvartnocore
  1142.         jmp    dvartloop        ; play it again Sam.
  1143. dvartnocore:
  1144.         mov    al,RELERR        ; super OOPS!
  1145.         jmp    putserr
  1146.  
  1147. releasepages    ENDP
  1148.  
  1149. ;-------------------------------------------------------------------------------
  1150.  
  1151. getpages    PROC    NEAR            ; get enough memory to load ovl
  1152.  
  1153.         ASSUME    DS:NOTHING,ES:ovltbl
  1154.  
  1155.         mov    ovlemshdl,-1        ; clear any EMS stuff
  1156.         and    ovlflg,NOT MASK ems
  1157.         mov    cx,ax
  1158.         add    cx,MEMCTLBLKSIZ     ; total paragraphs needed
  1159. dorkagain:
  1160.         call    largestmem        ; find largest free blk
  1161.         cmp    dx,cx            ; large enough?
  1162.         jnc    gotdork         ; yup.
  1163.         call    getemsmem        ; try to allocate ems
  1164.         cmp    dx,cx            ; any available ?
  1165.         jnc    gotdork
  1166. dorkkill:
  1167.         call    getvictim        ; select a victim to release
  1168.         call    killovl         ; kill the selected victim
  1169.         jmp    dorkagain
  1170. gotdork:
  1171.         jmp    splitblklow        ; split the free blk
  1172.  
  1173. getpages    ENDP
  1174.  
  1175. ;-------------------------------------------------------------------------------
  1176.  
  1177. splitblklow    PROC    NEAR
  1178.  
  1179. ; split a block of memory returning the lower one to be used.
  1180.  
  1181.         ASSUME    DS:NOTHING,ES:NOTHING
  1182.  
  1183.         push    es
  1184.         or    ds:memblkflg,MASK_used    ; set low block used
  1185.         call    splitblk
  1186.         jc    splitlowdone
  1187.         push    ds
  1188.         mov    ax,es
  1189.         mov    ds,ax
  1190.         call    mergemem        ; merge remaining free memory
  1191.         pop    ds
  1192. splitlowdone:
  1193.         pop    es
  1194.         mov    ds:memblkovl,es     ; fix ptr to ovl
  1195.         mov    ax,ds            ; return lower blk segment
  1196.         ret
  1197.  
  1198. splitblklow    ENDP
  1199.  
  1200. ;-------------------------------------------------------------------------------
  1201.  
  1202. splitblk    PROC    NEAR
  1203.  
  1204.         ASSUME    DS:NOTHING,ES:NOTHING
  1205.  
  1206.         mov    ax,ds
  1207.         add    ax,cx
  1208.         mov    es,ax            ; ^ to upper blk to be created
  1209.         mov    ax,ds:memblksiz
  1210.         sub    ax,cx
  1211.         jbe    nofix            ; must be at least 1 para remaining to split
  1212.         mov    ds:memblksiz,cx     ; fix blk sizes
  1213.         mov    es:memblksiz,ax
  1214.         mov    ax,ds:memblknxt     ; fix pointers
  1215.         mov    es:memblknxt,ax
  1216.         mov    ds:memblknxt,es
  1217.         mov    es:memblkprv,ds
  1218.         mov    es:memblkflg,0        ; set upper to not used
  1219.         mov    ax,es:memblknxt
  1220.         or    ax,ax
  1221.         jz    nofix
  1222.         push    ds
  1223.         mov    ds,ax            ; fix blk after upper to point to upper
  1224.         mov    ds:memblkprv,es
  1225.         pop    ds
  1226.         clc
  1227.         ret
  1228. nofix:
  1229.         stc
  1230.         ret
  1231.  
  1232. splitblk    ENDP
  1233.  
  1234. ;-------------------------------------------------------------------------------
  1235.  
  1236. largestmem    PROC    NEAR    ; returns seg in ax, size in dx
  1237.                 ; retruns first block that's large enough if possible
  1238.  
  1239.         ASSUME    DS:NOTHING,ES:ovltbl
  1240.  
  1241.         mov    ax,memblk1st        ; first mem blk
  1242.         xor    dx,dx            ; largest size found
  1243.         jmp    gook
  1244. gookloop:
  1245.         mov    ds,ax
  1246.         test    ds:memblkflg,MASK_used    ; is this blk used?
  1247.         jnz    gookme            ; yup
  1248.         cmp    ds:memblksiz,cx     ; is it large enough?
  1249.         jc    gookme            ; nope
  1250.         mov    dx,ds:memblksiz     ; got one!
  1251.         ret
  1252. gookme:
  1253.         mov    ax,ds:memblknxt
  1254. gook:
  1255.         or    ax,ax            ; end of list?
  1256.         jnz    gookloop        ; around and around
  1257.         ret
  1258.  
  1259. largestmem    ENDP
  1260.  
  1261. ;-------------------------------------------------------------------------------
  1262.  
  1263. killmem     PROC    NEAR
  1264.  
  1265.         ASSUME    DS:NOTHING,ES:ovltbl
  1266.  
  1267.         test    ds:memblkflg,MASK_used    ; is it used?
  1268.         jz    memnotused        ; don't kill ovl
  1269.         push    es
  1270.         mov    es,ds:memblkovl
  1271.         and    ovlflg,NOT MASK loaded    ; zap ovl associated with this blk
  1272.         and    ovlflg,NOT MASK ems
  1273.         pop    es
  1274. memnotused:
  1275.         jmp    mergemem        ; merge free memory
  1276.  
  1277. killmem     ENDP
  1278.  
  1279. ;-------------------------------------------------------------------------------
  1280.  
  1281. killovl     PROC    NEAR        ; preserves bx
  1282.  
  1283.         ASSUME    DS:ovltbl,ES:NOTHING
  1284.  
  1285.         mov    ds,ax
  1286.         and    ovlflg,NOT MASK loaded    ; ovl no longer loaded
  1287.         test    ovlflg,MASK ems     ; was it in ems ?
  1288.         jz    noemskill
  1289.         and    ovlflg,NOT MASK ems    ; no longer in ems
  1290.         mov    ax,ovlemshdl
  1291.         call    mappage
  1292. noemskill:
  1293.         mov    ax,ovlmemblk        ; get mem blk
  1294.         sub    ax,MEMCTLBLKSIZ
  1295.         mov    ds,ax
  1296.         jmp    mergemem        ; merge free memory
  1297.  
  1298. killovl     ENDP
  1299.  
  1300. ;-------------------------------------------------------------------------------
  1301.  
  1302. mergemem    PROC    NEAR
  1303.  
  1304. ; merge physically adjacent free memory blocks. Preserves es. ds -> a free block.
  1305.  
  1306.         ASSUME    DS:NOTHING,ES:NOTHING
  1307.  
  1308.         push    dx
  1309.         push    es
  1310.         and    ds:memblkflg,NOT MASK_used ; set current free
  1311.         mov    ax,ds:memblkprv     ; get previous blk
  1312.         or    ax,ax            ; was there a previous blk?
  1313.         jz    gibber            ; nope
  1314.         mov    es,ax
  1315.         test    es:memblkflg,MASK_used    ; is the previous blk used?
  1316.         jnz    gibber            ; yup
  1317.         add    ax,es:memblksiz     ; end of previous blk
  1318.         mov    dx,ds
  1319.         cmp    dx,ax            ; physically adjacent?
  1320.         jnz    gibber            ; nope
  1321.         mov    ax,ds:memblksiz
  1322.         add    es:memblksiz,ax     ; adjust size of new larger blk
  1323.         mov    ax,ds:memblknxt     ; fix pointers
  1324.         mov    es:memblknxt,ax
  1325.         or    ax,ax
  1326.         jz    almostgibber
  1327.         mov    ds,ax            ; fix pointer of next blk
  1328.         mov    ds:memblkprv,es
  1329. almostgibber:
  1330.         mov    ax,es
  1331.         mov    ds,ax            ; new blk segment
  1332. gibber:
  1333.         mov    ax,ds:memblknxt     ; get next blk
  1334.         or    ax,ax            ; was there a next blk?
  1335.         jz    killdone        ; nope
  1336.         mov    es,ax
  1337.         test    es:memblkflg,MASK_used    ; is the nxt blk used?
  1338.         jnz    killdone        ; yup
  1339.         mov    ax,ds
  1340.         add    ax,ds:memblksiz     ; end of this blk
  1341.         mov    dx,es
  1342.         cmp    ax,dx            ; physically adjacent?
  1343.         jnz    killdone        ; nope
  1344.         mov    ax,es:memblksiz
  1345.         add    ds:memblksiz,ax     ; adjust size of new larger blk
  1346.         mov    ax,es:memblknxt     ; fix pointers
  1347.         mov    ds:memblknxt,ax
  1348.         or    ax,ax
  1349.         jz    killdone
  1350.         mov    es,ax            ; fix pointer of blk after nxt
  1351.         mov    es:memblkprv,ds
  1352. killdone:
  1353.         and    ds:memblkflg,NOT MASK_used ; make sure it's free
  1354.         pop    es
  1355.         pop    dx
  1356.         mov    ax,ds
  1357.         ret
  1358.  
  1359. mergemem    ENDP
  1360.  
  1361. ;-------------------------------------------------------------------------------
  1362.  
  1363. getmoreram    PROC    NEAR            ; try to alloc remaining pieces
  1364.                         ; of memory if any
  1365.         ASSUME    DS:NOTHING,ES:NOTHING    ; return dx = biggest block
  1366.  
  1367.         push    cx
  1368.         push    bx
  1369.         push    si
  1370.         push    di
  1371.         push    ds
  1372.         push    es
  1373.         xor    dx,dx
  1374.         mov    ax,memblk1st
  1375. nxtlowblk:
  1376.         mov    ds,ax
  1377.         mov    ax,ds:memblknxt
  1378.         or    ax,ax
  1379.         jnz    nxtlowblk
  1380.  
  1381.         mov    si,OFFSET memblks    ; a place to store the handles
  1382.         mov    di,OFFSET tempmem    ; a place to store the rejects
  1383.         mov    cx,16            ; 16 more max
  1384. getramlp:
  1385.         mov    ah,DOSALLOC
  1386.         mov    bx,0ffffh        ; Everything
  1387.         int    DOS
  1388.         cmp    bx,10h            ; nothing smaller than .25k please
  1389.         jc    gotallram
  1390.         mov    ah,DOSALLOC        ; allocate our own memory
  1391.         int    DOS
  1392.         jc    gotallram        ; oops!
  1393.         cmp    ax,ovltblbse        ; is it after our first mem blk?
  1394.         jc    releaseblk
  1395.         cmp    dx,bx
  1396.         jnc    notbigger
  1397.         mov    dx,bx
  1398. notbigger:
  1399.         mov    cs:[si],ax        ; save it
  1400.         mov    es,ax
  1401.         mov    es:memblkflg,0        ; clear mem flags
  1402.         mov    es:memblknxt,0        ; set next to nothing
  1403.         mov    es:memblkovl,0        ; no overlays loaded
  1404.         mov    es:memblkprv,ds     ; point to previous
  1405.         mov    es:memblksiz,bx     ; allocated memory block size
  1406.         mov    ds:memblknxt,es     ; point to next
  1407.         add    si,2
  1408.         mov    ds,ax
  1409.         jmp    short getnxtram
  1410. releaseblk:
  1411.         mov    cs:[di],ax
  1412.         add    di,2
  1413. getnxtram:
  1414.         loop    getramlp
  1415. gotallram:
  1416.         mov    si,OFFSET tempmem
  1417.         mov    cx,16
  1418. releaselp:
  1419.         mov    ax,cs:[si]
  1420.         cmp    ax,-1
  1421.         jz    relnext
  1422.         mov    es,ax
  1423.         mov    ah,DOSFREE
  1424.         int    DOS
  1425.         mov    WORD PTR cs:[si],-1
  1426. relnext:
  1427.         add    si,2
  1428.         loop    releaselp
  1429.         pop    es
  1430.         pop    ds
  1431.         pop    di
  1432.         pop    si
  1433.         pop    bx
  1434.         pop    cx
  1435.         ret
  1436.  
  1437. getmoreram    ENDP
  1438.  
  1439. ;-------------------------------------------------------------------------------
  1440.  
  1441. getemsmem    PROC    NEAR
  1442.  
  1443.         ASSUME    DS:NOTHING,ES:ovltbl
  1444.  
  1445.         xor    dx,dx            ; no ems memory
  1446.         cmp    emmflg,-1
  1447.         jz    testemsslots
  1448.         ret
  1449. testemsslots:
  1450.         mov    curemshandle,-1
  1451.         mov    di,OFFSET emsmemblks
  1452.         mov    bx,cx
  1453.         mov    cx,16
  1454. emsfreeslot:
  1455.         mov    ax,cs:[di]
  1456.         cmp    ax, -1
  1457.         jz    gotemsslot
  1458.         call    mappage
  1459.         cmp    ax,bx
  1460.         jnc    foundpage
  1461.         add    di,2
  1462.         loop    emsfreeslot
  1463.         mov    cx,bx
  1464.         xor    dx,dx
  1465.         ret
  1466. gotemsslot:
  1467.         mov    cx,bx
  1468.         mov    bx,4
  1469.         mov    ah,EMMALLOC
  1470.         push    cx            ; paranoia ! shouldn't be necessary.
  1471.         push    di
  1472.         push    es
  1473.         int    EMM
  1474.         pop    es
  1475.         pop    di
  1476.         pop    cx
  1477.         or    ah,ah
  1478.         jz    gotsomeems
  1479.         xor    dx,dx
  1480.         ret
  1481. gotsomeems:
  1482.         mov    cs:[di],dx
  1483.         mov    ovlemshdl,dx
  1484.         or    ovlflg,MASK ems
  1485.         mov    ax,dx
  1486.         call    mapemspages
  1487.         mov    ax,emsframe
  1488.         mov    ds,ax
  1489.         mov    ds:memblkflg,0        ; clear mem flags
  1490.         mov    ds:memblknxt,0        ; set next to nothing
  1491.         mov    ds:memblkprv,0        ; set previous to nothing
  1492.         mov    ds:memblkovl,0        ; no overlay loaded
  1493.         mov    dx,1000h
  1494.         mov    ds:memblksiz,dx
  1495.         ret
  1496.  
  1497. foundpage:
  1498.         mov    cx,bx
  1499.         mov    ds,si
  1500.         mov    dx,ax
  1501.         mov    ax,cs:[di]
  1502.         mov    ovlemshdl,ax
  1503.         or    ovlflg,MASK ems
  1504.         ret
  1505.  
  1506. getemsmem    ENDP
  1507.  
  1508. ;-------------------------------------------------------------------------------
  1509.  
  1510. mappage     PROC    NEAR            ; map a 64K block of EMS mem.
  1511.  
  1512.         ASSUME    DS:NOTHING,ES:ovltbl
  1513.  
  1514.         cmp    ax,curemshandle
  1515.         jnz    doems
  1516.         ret
  1517. doems:
  1518.         push    bx
  1519.         push    dx
  1520.         push    ds
  1521.         push    es
  1522.         call    mapemspages
  1523.         mov    ax,emsframe
  1524.         xor    dx,dx
  1525.         xor    si,si
  1526. emsset:
  1527.         mov    ds,ax
  1528.         test    ds:memblkflg,MASK_used    ; mem blk used ?
  1529.         jz    emsfreeblk
  1530.         mov    es,ds:memblkovl
  1531.         or    ovlflg,MASK ems OR MASK loaded
  1532.         jmp    emsnext
  1533. emsfreeblk:
  1534.         mov    ax,ds:memblksiz
  1535.         cmp    dx,ax
  1536.         jnc    emsnext
  1537.         mov    dx,ax
  1538.         mov    si,ds
  1539. emsnext:
  1540.         mov    ax,ds:memblknxt
  1541.         or    ax,ax
  1542.         jnz    emsset
  1543.  
  1544.         mov    ax,dx
  1545.         pop    es
  1546.         pop    ds
  1547.         pop    dx
  1548.         pop    bx
  1549.         ret
  1550.  
  1551. mappage     ENDP
  1552.  
  1553. ;-------------------------------------------------------------------------------
  1554.  
  1555. mapemspages    PROC    NEAR
  1556.  
  1557.         ASSUME    DS:NOTHING,ES:ovltbl
  1558.  
  1559.         push    es
  1560.         push    bx
  1561.         push    cx
  1562.         push    dx
  1563.         mov    curemshandle,ax
  1564.         mov    dx,ax
  1565.         mov    ah,EMMMAP
  1566.         xor    al,al            ; physical page 0
  1567.         xor    bx,bx            ; logical page 0
  1568.         push    dx
  1569.         int    EMM
  1570.         pop    dx
  1571.         or    ah,ah
  1572.         jnz    emmerror
  1573.         mov    ah,EMMMAP
  1574.         mov    al,1            ; physical page 1
  1575.         mov    bx,1            ; logical page 1
  1576.         push    dx
  1577.         int    EMM
  1578.         pop    dx
  1579.         or    ah,ah
  1580.         jnz    emmerror
  1581.         mov    ah,EMMMAP
  1582.         mov    al,2            ; physical page 2
  1583.         mov    bx,2            ; logical page 2
  1584.         push    dx
  1585.         int    EMM
  1586.         pop    dx
  1587.         or    ah,ah
  1588.         jnz    emmerror
  1589.         mov    ah,EMMMAP
  1590.         mov    al,3            ; physical page 3
  1591.         mov    bx,3            ; logical page 3
  1592.         int    EMM
  1593.         or    ah,ah
  1594.         jnz    emmerror
  1595.         mov    es,ovltblbse
  1596.         mov    cx,ovlcnt
  1597.         xor    bx,bx
  1598. testems:
  1599.         test    ovlflg[bx],MASK ems
  1600.         jz    nxttestems
  1601.         and    ovlflg[bx],NOT MASK loaded
  1602. nxttestems:
  1603.         add    bx,OVLSEGSIZ
  1604.         loop    testems
  1605.         pop    dx
  1606.         pop    cx
  1607.         pop    bx
  1608.         pop    es
  1609.         ret
  1610.  
  1611. emmerror:
  1612.         mov    al,EMSERR        ; ems manager error
  1613.         jmp    putserr
  1614.  
  1615. mapemspages    ENDP
  1616.  
  1617. ;-------------------------------------------------------------------------------
  1618.  
  1619. gethdr        PROC    NEAR            ; read EXE header from handle
  1620.  
  1621.         ASSUME    DS:NOTHING,ES:NOTHING
  1622.  
  1623.         push    cx
  1624.         push    ds
  1625.         mov    ax,cs
  1626.         mov    ds,ax
  1627.         mov    dx,OFFSET hdr        ; a place to put it
  1628.         mov    bx,ovlexefilhdl     ; the file handle
  1629.         mov    cx,TYPE EXEHDR        ; header size in bytes
  1630.         mov    ah,DOSREAD
  1631.         int    DOS            ; read from file
  1632.         jc    exegone         ; oops
  1633.         cmp    ax,cx            ; got correct number of bytes?
  1634.         jnz    exegone         ; nope
  1635.         pop    ds
  1636.         pop    cx
  1637.         ret                ; Wow, it worked!
  1638. exegone:
  1639.         mov    al,HDRERR        ; You lose!
  1640.         jmp    putserr
  1641.  
  1642. gethdr        ENDP
  1643.  
  1644. ;-------------------------------------------------------------------------------
  1645.  
  1646. putserr     PROC    NEAR
  1647.  
  1648. ; display error msg, close file, restore int vectors, free mem and return to DOS.
  1649.  
  1650.         ASSUME    DS:NOTHING,ES:NOTHING
  1651.  
  1652.         xor    ah,ah
  1653.         push    ax            ; keep return code for later
  1654.         push    cs
  1655.         pop    ds
  1656.         mov    bx,ax
  1657.         shl    bx,1
  1658.         add    bx,OFFSET errortbl
  1659.         mov    dx,[bx]
  1660.         cmp    dx,-1
  1661.         jz    freeints
  1662.         push    dx
  1663.         mov    dx,OFFSET msghead
  1664.         mov    ah,PRINT
  1665.         int    DOS
  1666.         pop    dx
  1667.         mov    ah,PRINT
  1668.         int    DOS            ; display error msg
  1669.  
  1670.         mov    ah,PRINT
  1671.         mov    dx,OFFSET diag
  1672.         int    DOS
  1673.         pop    ax
  1674.         push    ax
  1675.         call    itoa            ; error number
  1676.         mov    ah,DOSPUTC
  1677.         mov    dl,':'
  1678.         int    DOS
  1679.         mov    ax,VERSION
  1680.         call    itoa            ; version number
  1681.         mov    ah,DOSPUTC
  1682.         mov    dl,':'
  1683.         int    DOS
  1684.         mov    ax,0a000h
  1685.         sub    ax,ovltblbse        ; conventional memory
  1686.         call    itoa
  1687.         mov    ah,DOSPUTC
  1688.         mov    dl,':'
  1689.         int    DOS
  1690.         mov    si,OFFSET emsmemblks
  1691.         mov    cx,16
  1692.         xor    ax,ax
  1693. emstotlp:
  1694.         cmp    WORD PTR cs:[si],-1
  1695.         jz    gotemstot
  1696.         add    ax,emmframesiz
  1697.         add    si,2
  1698.         loop    emstotlp
  1699. gotemstot:
  1700.         call    itoa            ; ems usage in blocks
  1701.         mov    ah,DOSPUTC
  1702.         mov    dl,')'
  1703.         int    DOS
  1704.  
  1705.         mov    dx,OFFSET msgtail
  1706.         mov    ah,PRINT
  1707.         int    DOS
  1708. freeints:
  1709.         call    rstvectors        ; restore all int vectors
  1710.  
  1711.         mov    ax,ovltblbse
  1712.         cmp    ax,-1
  1713.         jz    freememblks
  1714.         mov    es,ax
  1715.         mov    ah,DOSFREE
  1716.         int    DOS
  1717. freememblks:
  1718.         mov    cx,16            ; do all allocated mem blocks
  1719.         mov    si,OFFSET memblks
  1720. freememlp:
  1721.         mov    ax,cs:[si]        ; get memory blk segment
  1722.         cmp    ax,-1            ; was one ever allocated?
  1723.         jz    nxtmemlp        ; nope
  1724.         mov    es,ax
  1725.         mov    ah,DOSFREE        ; must free it.
  1726.         int    DOS
  1727. nxtmemlp:
  1728.         add    si,2
  1729.         loop    freememlp
  1730.         mov    cx,16            ; do all allocated ems blocks
  1731.         mov    si,OFFSET emsmemblks
  1732. freeemsmemlp:
  1733.         mov    dx,cs:[si]        ; get memory blk segment
  1734.         cmp    dx,-1            ; was one ever allocated?
  1735.         jz    nxtemsmemlp        ; nope
  1736.         mov    ah,EMMFREE        ; must free it.
  1737.         int    EMM
  1738. nxtemsmemlp:
  1739.         add    si,2
  1740.         loop    freeemsmemlp
  1741. closefile:
  1742.         mov    bx,ovlexefilhdl     ; get file handle
  1743.         cmp    bx,-1            ; was the file ever opened?
  1744.         jz    byebye            ; nope
  1745.         mov    ah,DOSCLOSE        ; close it
  1746.         int    DOS
  1747. byebye:
  1748.         pop    ax            ; return code in al
  1749.         mov    ah,TERMINATE
  1750.         int    DOS            ; terminate this process
  1751.  
  1752. putserr     ENDP
  1753.  
  1754. ;-------------------------------------------------------------------------------
  1755.  
  1756. itoa        PROC    NEAR
  1757.  
  1758.         push    ax
  1759.         xchg    ah,al
  1760.         call    putbyte
  1761.         pop    ax
  1762.         jmp    putbyte
  1763.  
  1764. itoa        ENDP
  1765.  
  1766. ;-------------------------------------------------------------------------------
  1767.  
  1768. putbyte     PROC    NEAR
  1769.  
  1770.         push    ax
  1771.         shr    al,1
  1772.         shr    al,1
  1773.         shr    al,1
  1774.         shr    al,1
  1775.         call    nibble
  1776.         pop    ax
  1777.         jmp    nibble
  1778.  
  1779. putbyte     ENDP
  1780.  
  1781. ;-------------------------------------------------------------------------------
  1782.  
  1783. nibble        PROC    NEAR
  1784.  
  1785.         and    al,0fh
  1786.         add    al,30h
  1787.         cmp    al,3ah
  1788.         jc    nibok
  1789.         add    al,7
  1790. nibok:
  1791.         mov    dl,al
  1792.         mov    ah,DOSPUTC
  1793.         int    DOS
  1794.         ret
  1795.  
  1796. nibble        ENDP
  1797.  
  1798. ;-------------------------------------------------------------------------------
  1799.  
  1800. setvectors    PROC    NEAR
  1801.  
  1802.         push    ds
  1803.         xor    ax,ax
  1804.         mov    ds,ax
  1805.         mov    si,cs:intnum
  1806.         cli
  1807.         mov    ax,[si]
  1808.         mov    WORD PTR cs:oldvec,ax    ; save original vector
  1809.         mov    ax,[si+2]
  1810.         mov    WORD PTR cs:oldvec+2,ax
  1811.         mov    ax,OFFSET ovlmgr    ; point to ovlmgr
  1812.         mov    [si],ax         ; set int vector
  1813.         mov    [si+2],cs
  1814.  
  1815.         mov    si,DOS*4
  1816.         mov    ax,[si]
  1817.         mov    WORD PTR cs:oldint21,ax ; save original vector
  1818.         mov    ax,[si+2]
  1819.         mov    WORD PTR cs:oldint21+2,ax
  1820.         mov    ax,OFFSET int21     ; point to new int21
  1821.         mov    [si],ax         ; set int vector
  1822.         mov    [si+2],cs
  1823.         sti
  1824.         pop    ds
  1825.         ret
  1826.  
  1827. setvectors    ENDP
  1828.  
  1829. ;-------------------------------------------------------------------------------
  1830.  
  1831. rstvectors    PROC    NEAR
  1832.  
  1833.         push    ds
  1834.         xor    ax,ax
  1835.         mov    ds,ax
  1836.         mov    si,DOS*4
  1837.         cli
  1838.         mov    ax,WORD PTR cs:oldint21 ; put back dos vector
  1839.         cmp    ax,-1
  1840.         jz    rstvec
  1841.         mov    [si],ax
  1842.         mov    ax,WORD PTR cs:oldint21+2
  1843.         mov    [si+2],ax
  1844. rstvec:
  1845.         mov    si,cs:intnum
  1846.         mov    ax,WORD PTR cs:oldvec    ; put back ovlmgr vector
  1847.         cmp    ax,-1
  1848.         jz    rstdone
  1849.         mov    [si],ax
  1850.         mov    ax,WORD PTR cs:oldvec+2
  1851.         mov    [si+2],ax
  1852.         sti
  1853. rstdone:
  1854.         pop    ds
  1855.         ret
  1856.  
  1857. rstvectors    ENDP
  1858.  
  1859. code        ENDS
  1860.  
  1861.         END
  1862.